package com.jrx.anytxn.transaction.timer.job.cancle.config;

import com.jrx.anytxn.common.data.TxnRespCode;
import com.jrx.anytxn.common.exception.TxnBizException;
import com.jrx.anytxn.customer.constant.CustomerConstant;
import com.jrx.anytxn.redisson.service.RedissonLockService;
import com.jrx.anytxn.redisson.util.LockType;
import com.jrx.anytxn.ribbon.config.GrayVersionConfig;
import com.jrx.anytxn.transaction.constant.TransBizConstant;
import com.jrx.anytxn.transaction.entity.TlDisbursementLog;
import com.jrx.anytxn.transaction.handler.ILoanHandler;
import com.jrx.anytxn.transaction.mapper.ext.ExtTlDisbursementLogMapper;
import com.jrx.anytxn.transaction.timer.config.AnytxnBatchProperties;
import org.redisson.api.RLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 放款失败撤销订单任务
 *
 */
@Configuration
@EnableConfigurationProperties(AnytxnBatchProperties.class)
public class CancleLoanConfiguration {

    private static final Logger logger = LoggerFactory.getLogger(CancleLoanConfiguration.class);

    @Autowired
    public JobBuilderFactory jobBuilderFactory;

    @Autowired
    public StepBuilderFactory stepBuilderFactory;

    @Autowired
    AnytxnBatchProperties anytxnBatchProperties;

    @Autowired
    ExtTlDisbursementLogMapper extTlDisbursementLogMapper;

    @Autowired
    ILoanHandler loanHandler;

    @Autowired
    private RedissonLockService redissonLockService;

    @Autowired
    public GrayVersionConfig grayVersionConfig;

    @Bean
    public Job cancelLoanJob() {
        return jobBuilderFactory.get("cancelLoanJob")
                .start(cancelLoanStep())
                .build();
    }

    @Bean
    public Step cancelLoanStep() {
        return stepBuilderFactory.get("cancelLoanStep")
                .tasklet(cancelLoanTasklet())
                .build();
    }

    @Bean
    @StepScope
    public Tasklet cancelLoanTasklet() {
        logger.info("撤销订单JOB开始");
        return (stepContribution, chunkContext) -> {
            List<TlDisbursementLog> logList = extTlDisbursementLogMapper.selectBySumStatusAndCancelStatusAndCancelWhenFail(TransBizConstant.DISBURSEMENT_LOG_SUM_STATUS_F,TransBizConstant.NO_FLAG,TransBizConstant.CANCLE_STATUS_1, grayVersionConfig.getCurrentVersion());
            ExecutorService service = Executors.newFixedThreadPool(anytxnBatchProperties.getCancleLoanConfig().getThrottleLimit());
            List<CompletableFuture<Void>> list = logList.stream().map(log ->
                    CompletableFuture.runAsync(() ->
                            {
                                String lockKey = String.format(CustomerConstant.LOAN_REDIS_LOCK,log.getTenantId(),
                                        log.getCustomerId());
                                logger.info("RedissionLock key:{}",lockKey);
                                RLock lock = redissonLockService.getRLock(lockKey, LockType.REENTRANT_LOCK);
                                try {
                                    boolean lockFlag = lock.tryLock(CustomerConstant.LOAN_REDIS_LOCK_WAITE_TIME,
                                            CustomerConstant.LOAN_REDIS_LOCK_LESS_TIME, TimeUnit.SECONDS);
                                    logger.info("获取RedissionLock key:{},lockFlag:{}",lockKey,lockFlag);
                                    if(!lockFlag) {
                                        logger.error(TxnRespCode.TRANSACTION_PROCESSING.getMsg());
                                        throw new TxnBizException(TxnRespCode.TRANSACTION_PROCESSING.getCode(),TxnRespCode.TRANSACTION_PROCESSING.getMsg());
                                    }
                                    loanHandler.cancelOrderWithDisbursementLog(log);
                                } catch (Exception e) {
                                    logger.error("差错异常：",e);
                                }finally {
                                    if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) {
                                        lock.unlock();
                                    }
                                }
                            }
                    , service)
            ).collect(Collectors.toList());
            long count = list.stream().map(CompletableFuture::join).count();
            logger.info("撤销订单最终结果数{}",count);
            service.shutdown();
            return RepeatStatus.FINISHED;
        };
    }
}
